package io.github.zatter.qiniucorejava.utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.zatter.qiniucorejava.utils.model.VoiceApiResponse;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * {@code @Author: soyo}
 * {@code @Description: 文本转语音服务（修复超时+增加重试）}
 * {@code @Create: 2025/9/23}
 */
@Service
@Slf4j
public class TextToVoiceService {
    private final String baseUrl;
    private final String apiKey;
    private final String voiceType;
    private final String encoding;
    private final double speedRatio;
    private final ObjectMapper objectMapper;
    private final OkHttpClient okHttpClient;
    // 重试配置：最多重试3次，每次间隔1秒
    private static final int MAX_RETRY_COUNT = 3;
    private static final long RETRY_INTERVAL_MS = 1000;

    public TextToVoiceService() {
        this.baseUrl = "https://openai.qiniu.com/v1";
        this.apiKey = "sk-610453bad9743dfb294ae3234ada68874c4c1640e6c4cd716dfac043a774eb21";
        this.voiceType = "qiniu_zh_female_tmjxxy";
        this.encoding = "mp3";
        this.speedRatio = 1.0;
        this.objectMapper = new ObjectMapper();

        // 核心修改1：配置OkHttpClient超时（解决超时问题）
        this.okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)    // 连接超时：30秒（建立连接的时间）
                .readTimeout(120, TimeUnit.SECONDS)     // 读取超时：120秒（等待API响应的核心配置）
                .writeTimeout(30, TimeUnit.SECONDS)     // 写入超时：30秒（发送请求体的时间）
                .build();
    }

    /**
     * 将文字转换为语音（主方法）
     */
    public byte[] textToSpeech(String text) {
        try {
            log.info("开始语音生成，文本长度: {} 字符", text.length());

            // 核心修改2：调用带重试的API方法（应对网络波动）
            String responseBody = callVoiceApiWithRetry(text);

            // 解析响应
            VoiceApiResponse apiResponse = parseVoiceApiResponse(responseBody);

            if (apiResponse.getData() != null && !apiResponse.getData().isEmpty()) {
                // 解码Base64音频数据
                byte[] audioData = decodeBase64Audio(apiResponse.getData());
                log.info("语音生成成功，音频大小: {} bytes，时长: {} 毫秒",
                        audioData.length, apiResponse.getDuration());
                return audioData;
            } else {
                log.warn("语音API返回数据格式异常");
                throw new RuntimeException("语音API返回的音频数据为空");
            }

        } catch (Exception e) {
            log.error("语音生成失败: {}", e.getMessage(), e);
            throw new RuntimeException("语音生成失败: " + e.getMessage(), e);
        }
    }

    /**
     * 带重试的API调用（核心新增方法）
     */
    private String callVoiceApiWithRetry(String text) throws Exception {
        Exception lastException = null;
        // 循环重试：最多MAX_RETRY_COUNT次
        for (int retry = 1; retry <= MAX_RETRY_COUNT; retry++) {
            try {
                return callVoiceApi(text); // 调用实际API方法
            } catch (Exception e) {
                lastException = e;
                // 只对超时/网络异常重试，非网络错误（如API返回400）不重试
                if (!(e instanceof java.net.SocketTimeoutException || e instanceof IOException)) {
                    log.warn("非网络异常，无需重试（第{}次）：{}", retry, e.getMessage());
                    break;
                }
                // 重试提示日志
                log.warn("语音API调用第{}次失败（共{}次），原因：{}，{}毫秒后重试",
                        retry, MAX_RETRY_COUNT, e.getMessage(), RETRY_INTERVAL_MS);
                // 重试间隔：避免频繁请求给API施压
                Thread.sleep(RETRY_INTERVAL_MS);
            }
        }
        // 重试耗尽仍失败，抛出最终异常
        throw new RuntimeException("语音API调用失败（已重试" + MAX_RETRY_COUNT + "次）", lastException);
    }

    /**
     * 使用 OkHttp 调用语音合成API（原方法保留，无修改）
     */
    private String callVoiceApi(String text) {
        try {
            // 构建请求体
            Map<String, Object> requestBody = buildTTSRequest(text);
            String jsonBody = objectMapper.writeValueAsString(requestBody);

            RequestBody body = RequestBody.create(
                    jsonBody,
                    MediaType.parse("application/json; charset=utf-8")
            );

            String ttsUrl = baseUrl + "/voice/tts";
            log.debug("调用语音合成API: {}", ttsUrl);

            Request request = new Request.Builder()
                    .url(ttsUrl)
                    .addHeader("Authorization", "Bearer " + apiKey)
                    .post(body)
                    .build();

            try (Response response = okHttpClient.newCall(request).execute()) {
                if (response.isSuccessful() && response.body() != null) {
                    return response.body().string();
                } else {
                    // 补充响应体日志，方便排查API错误（如参数错误）
                    String errorBody = response.body() != null ? response.body().string() : "无响应体";
                    throw new RuntimeException("语音API返回异常状态: " + response.code() +
                            " - " + response.message() + "，错误详情：" + errorBody);
                }
            }

        } catch (Exception e) {
            log.error("语音生成API调用失败", e);
            throw new RuntimeException("语音API调用失败: " + e.getMessage(), e);
        }
    }

    // 以下方法无修改，保留原逻辑
    private Map<String, Object> buildTTSRequest(String text) {
        Map<String, Object> requestBody = new HashMap<>();
        Map<String, Object> audio = new HashMap<>();
        audio.put("voice_type", voiceType);
        audio.put("encoding", encoding);
        audio.put("speed_ratio", speedRatio);
        Map<String, String> request = new HashMap<>();
        request.put("text", text);
        requestBody.put("audio", audio);
        requestBody.put("request", request);
        log.debug("语音合成请求体: {}", requestBody);
        return requestBody;
    }

    private VoiceApiResponse parseVoiceApiResponse(String responseBody) {
        try {
            log.debug("解析语音API响应: {}", responseBody.substring(0, Math.min(200, responseBody.length())));
            JsonNode jsonNode = objectMapper.readTree(responseBody);
            VoiceApiResponse response = new VoiceApiResponse();
            response.setReqid(jsonNode.path("reqid").asText());
            response.setOperation(jsonNode.path("operation").asText());
            response.setSequence(jsonNode.path("sequence").asInt());
            response.setData(jsonNode.path("data").asText());
            JsonNode additionNode = jsonNode.path("addition");
            if (!additionNode.isMissingNode()) {
                String duration = additionNode.path("duration").asText();
                response.setDuration(duration);
            }
            log.debug("语音API响应解析成功 - reqid: {}, duration: {} ms",
                    response.getReqid(), response.getDuration());
            return response;
        } catch (Exception e) {
            log.error("解析语音API响应失败", e);
            throw new RuntimeException("解析语音API响应失败", e);
        }
    }

    private byte[] decodeBase64Audio(String base64Data) {
        try {
            log.debug("开始解码Base64音频数据，数据长度: {} 字符", base64Data.length());
            byte[] audioBytes = Base64.getDecoder().decode(base64Data);
            log.debug("Base64音频数据解码成功，音频大小: {} bytes", audioBytes.length);
            return audioBytes;
        } catch (Exception e) {
            log.error("Base64音频数据解码失败: {}", e.getMessage(), e);
            throw new RuntimeException("Base64音频数据解码失败", e);
        }
    }
}
